package config

import "gopkg.in/yaml.v2"

type Builder struct {
	Client                 *Client          `yaml:"client"`
	Chains                 *Chains          `yaml:"chains"`
	Organizations          *Organizations   `yaml:"organizations"`
	Consensers             *Consensers      `yaml:"consensers"`
	Inodes                 *Inodes          `yaml:"inodes"`
	CertificateAuthorities *CertAuthorities `yaml:"certificateAuthorities,omitempty"`
}

// NewBuilder
// @Description: 创建一个配置生成器，使用方法NewBuilder().SetClient().SetChannels()
// @return *Config
func NewBuilder() *Builder {
	return &Builder{}
}

func (c *Builder) Type() string {
	return "yaml"
}

func (c *Builder) Bytes() []byte {
	bytes, _ := yaml.Marshal(c)
	return bytes
}

// SetClient
// @Description: 设置客户端配置
// @param Client
// @return *Config
func (c *Builder) SetClient(client *Client) *Builder {
	c.Client = client
	return c
}

// SetChains
// @Description: 设置通道配置
// @param Chains
// @return *Config
func (c *Builder) SetChains(chains *Chains) *Builder {
	c.Chains = chains
	return c
}

// SetOrgs
// @Description: 设置组织配置
// @param orgs
// @return *Config
func (c *Builder) SetOrgs(orgs *Organizations) *Builder {
	c.Organizations = orgs
	return c
}

// SetConsensers
// @Description: 设置consenser节点配置
// @param Consensers
// @return *Config
func (c *Builder) SetConsensers(consensers *Consensers) *Builder {
	c.Consensers = consensers
	return c
}

// SetInodes
// @Description: 设置inode节点配置
// @param Inodes
// @return *Config
func (c *Builder) SetInodes(inodes *Inodes) *Builder {
	c.Inodes = inodes
	return c
}

// SetCertAuthorities
// @Description: 设置CA配置
// @param ca
// @return *Config
func (c *Builder) SetCertAuthorities(ca *CertAuthorities) *Builder {
	c.CertificateAuthorities = ca
	return c
}

// Client
// @Description: 配置中客户端配置部分
type Client struct {
	Org string `yaml:"organization"`
	Log struct {
		Level string `yaml:"level"`
	} `yaml:"logging,omitempty"`
	CryptoConfig    Credential      `yaml:"cryptoconfig,omitempty"`
	CredentialStore credentialStore `yaml:"credentialStore"`
	BCCSP           bccsp           `yaml:"BCCSP"`
	TlsCerts        tlsCerts        `yaml:"tlsCerts"`
}

type Credential struct {
	Path string `yaml:"path,omitempty"`
	Pem  string `yaml:"pem,omitempty"`
}

type GrpcOptions struct {
	OverName string `yaml:"ssl-target-name-override"`
}

type credentialStore struct {
	Path        string     `yaml:"path"`
	CryptoStore Credential `yaml:"cryptoStore,omitempty"`
}

// BCCSP
// @Description: 加密模块配置
type bccsp struct {
	Security struct {
		Enabled bool `yaml:"enabled,omitempty"`
		Default struct {
			Provider string `yaml:"provider"`
		} `yaml:"default"`
		HashAlgorithm string `yaml:"hashAlgorithm"`
		Level         int    `yaml:"level"`
	} `yaml:"security,omitempty"`
}

type tlsCerts struct {
	SystemCertPool bool   `yaml:"systemCertPool,omitempty"`
	Path           string `yaml:"path,omitempty"`
	Pem            string `yaml:"pem,omitempty"`
	Client         struct {
		Key  *Credential `yaml:"key,omitempty"`
		Cert *Credential `yaml:"cert,omitempty"`
	} `yaml:"client,omitempty"`
}

// NewFile
// @Description: 创建一个证书/密钥配置
// @return *credential
func NewCredential() *Credential {
	return &Credential{}
}

// SetPath
// @Description: 设置文件路径
// @param path
// @return *credential
func (f *Credential) SetPath(path string) *Credential {
	f.Path = path
	return f
}

// SetPem
// @Description: 设置pem数据
// @param pem
// @return *credential
func (f *Credential) SetPem(pem string) *Credential {
	f.Pem = pem
	return f
}

// NewClient
// @Description: 创建客户端配置
// @return *Client
func NewClient() *Client {
	return &Client{}
}

// SetOrg
// @Description: 设置客户端organization
// @return *Client
func (c *Client) SetOrg(org string) *Client {
	c.Org = org
	return c
}

// SetLogLevel
// @Description: 设置日志等级
func (c *Client) SetLogLevel(level string) *Client {
	c.Log.Level = level
	return c
}

// SetCryptoConfig
// @Description: 组织管理证书和密钥的根目录，如果组织加密路径是相对地址，则用这个配置+组织加密路径
func (c *Client) SetCryptoConfig(path string) *Client {
	c.CryptoConfig.Path = path
	return c
}

func (c *Client) SetCredentialStore(path string, cryptoStorePath string) *Client {
	c.CredentialStore.Path = path
	c.CredentialStore.CryptoStore.Path = cryptoStorePath
	return c
}

// SetBCCSP
// @Description: 设置加密模块的加密算法和hash算法
// @param algo 加密算法  SW,GM
// @param hash 哈希算法  SHA2,SM3
// @param level 安全等级  默认256
// @return *Client
func (c *Client) SetBCCSP(algo, hash string, level int) *Client {
	c.BCCSP.Security.Enabled = true
	c.BCCSP.Security.Default.Provider = algo
	c.BCCSP.Security.HashAlgorithm = hash
	c.BCCSP.Security.Level = level
	return c
}

func (c *Client) EnableSystemCertPool() *Client {
	c.TlsCerts.SystemCertPool = true
	return c
}

func (c *Client) SetTlsClient(cert, key *Credential) *Client {
	c.TlsCerts.Client.Cert = cert
	c.TlsCerts.Client.Key = key
	return c
}

type Chains map[string]*chain

type chain struct {
	Consensers []string                     `yaml:"consensers"`
	Inodes     *map[string]*map[string]bool `yaml:"inodes"`
}

// NewChains
// @Description: 创建通道配置
// @return *Chains
func NewChains() *Chains {
	return &Chains{}
}

// AddChain
// @Description: 添加Chain
func (c Chains) AddChain(chainName string, consensers, inodes []string) *Chains {
	nodes := make(map[string]*map[string]bool)
	roles := make(map[string]bool)
	roles["endorsingInode"] = true
	roles["contractQuery"] = true
	roles["ledgerQuery"] = true
	roles["eventSource"] = true

	for _, inode := range inodes {
		nodes[inode] = &roles
	}
	c[chainName] = &chain{
		Consensers: consensers,
		Inodes:     &nodes,
	}
	return &c
}

type Organization struct {
	IamId                  string           `yaml:"iamid"`
	CryptoPath             string           `yaml:"cryptoPath"`
	Inodes                 []string         `yaml:"inodes"`
	CertificateAuthorities []string         `yaml:"certificateAuthorities,omitempty"`
	Users                  map[string]*user `yaml:"users,omitempty"`
}

type user struct {
	Key  *Credential `yaml:"key,omitempty"`
	Cert *Credential `yaml:"cert,omitempty"`
}

// NewOrg
// @Description: 创建组织配置
// @return *Organization
func NewOrg() *Organization {
	return &Organization{
		Users: make(map[string]*user),
	}
}

func (o *Organization) SetIAMId(id string) *Organization {
	o.IamId = id
	return o
}
func (o *Organization) SetCryptoPath(path string) *Organization {
	o.CryptoPath = path
	return o
}
func (o *Organization) SetInode(inodes []string) *Organization {
	o.Inodes = inodes
	return o
}

func (o *Organization) SetCertAuthority(certAuthorities []string) *Organization {
	o.CertificateAuthorities = certAuthorities
	return o
}
func (o *Organization) AddUser(userName string, cert, key *Credential) *Organization {
	o.Users[userName] = &user{
		Key:  key,
		Cert: cert,
	}
	return o
}

type Organizations map[string]*Organization

func NewOrgs() *Organizations {
	return &Organizations{}
}

// AddOrg
// @Description: 添加组织
// @return *Organizations
func (o Organizations) AddOrg(orgName string, org *Organization) *Organizations {
	o[orgName] = org
	return &o
}

type Consensers map[string]*node

type node struct {
	Url         string       `yaml:"url"`
	TlsCACerts  *Credential  `yaml:"tlsCACerts,omitempty"`
	GrpcOptions *GrpcOptions `yaml:"grpcOptions,omitempty"`
}

// NewConsensers
// @Description: 创建Consenser节点配置
// @return *Consensers
func NewConsensers() *Consensers {
	return &Consensers{}
}

// AddConsenser
// @Description: 添加Consenser节点
// @return *Consensers
func (c Consensers) AddConsenser(name, url string, tlsCACerts *Credential) *Consensers {
	c[name] = &node{
		Url:        url,
		TlsCACerts: tlsCACerts,
		GrpcOptions: &GrpcOptions{
			OverName: name,
		},
	}
	return &c
}

type Inodes map[string]*node

// NewInodes
// @Description: 创建Inode节点配置
// @return *Inodes
func NewInodes() *Inodes {
	return &Inodes{}
}

// AddInode
// @Description: 添加inode节点
// @return *Inodes
func (i Inodes) AddInode(name, url string, tlsCACerts *Credential) *Inodes {
	i[name] = &node{
		Url:        url,
		TlsCACerts: tlsCACerts,
		GrpcOptions: &GrpcOptions{
			OverName: name,
		},
	}
	return &i
}

type CertAuthority struct {
	Url        string   `yaml:"url"`
	TlsCACerts tlsCerts `yaml:"tlsCACerts"`
	Registrar  struct {
		EnrollId     string `yaml:"enrollId"`
		EnrollSecret string `yaml:"enrollSecret"`
	} `yaml:"registrar"`
	CAName string `yaml:"caName"`
}

// NewCertAuthority
// @Description: 创建CA配置
// @return *certAuthority
func NewCertAuthority() *CertAuthority {
	return &CertAuthority{}
}

func (c *CertAuthority) SetURL(url string) *CertAuthority {
	c.Url = url
	return c
}

func (c *CertAuthority) SetTlsCACert(cert *Credential) *CertAuthority {
	c.TlsCACerts.Path = cert.Path
	c.TlsCACerts.Pem = cert.Pem
	return c
}

func (c *CertAuthority) SetTlsClient(cert, key *Credential) *CertAuthority {
	c.TlsCACerts.Client.Cert = cert
	c.TlsCACerts.Client.Key = key
	return c
}

func (c *CertAuthority) SetRegistrar(enrollId, enrollSecret string) *CertAuthority {
	c.Registrar.EnrollId = enrollId
	c.Registrar.EnrollSecret = enrollSecret
	return c
}
func (c *CertAuthority) SetCAName(caName string) *CertAuthority {
	c.CAName = caName
	return c
}

type CertAuthorities map[string]*CertAuthority

// NewCertAuthorities
// @Description: 创建CA配置
// @return *CertAuthorities
func NewCertAuthorities() *CertAuthorities {
	return &CertAuthorities{}
}

// AddCertAuthority
// @Description: 添加CA
// @return *CertAuthorities
func (c CertAuthorities) AddCertAuthority(name string, ca *CertAuthority) *CertAuthorities {
	c[name] = ca
	return &c
}
